package com.aispeech.asr.apis.ssc.data.form;

import com.aispeech.asr.comm.enums.EAudioType;
import com.aispeech.asr.comm.enums.ErrorCode;
import com.aispeech.asr.comm.exceptions.AsrException;
import com.aispeech.asr.comm.utils.BeanUtils;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import reactor.core.publisher.Mono;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

@Data
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class CreateTaskForm {
    private String appId;
    private String AudioId;
    private String filePath;
    private String organization;
    private String userId;
    private long fileLen;
    private long checkLength;
    private String audioType;
    private String res;
    private String lang;
    private int sampleRate = 16000; // #TODO：客户端如果传错了就惨了
    private int speakerRate;
    private int channel = 1;
    private int sampleBytes = 2;
    private int taskType = 1;
    //private String phraseFileId = "0";
    //private String hotwords = "";
    //private String lmid = "";
    //private String sensitiveFileId = "0";
    private String callback;
    private int speakerNumber = 0;
    //private int useTxtSmooth = 1;
    //private int useInverseTxt = 1;
    //private int useFullstop = 0;
    private int useMetrics = 0;
    //private int useWpe = 0;
    //private int useAux = 0;
    //private int useSegment = 0;
    //private int useParagraph = 0;
    private int debug = 0;

    public static Mono<CreateTaskForm> from(String productId, Map<String, String> stringStringMap) {
        try {
            CreateTaskForm form = BeanUtils.mapToBean(stringStringMap, CreateTaskForm.class);
            form.setAppId(productId);

            ErrorCode errCode = checkRequired(form);
            if (errCode == ErrorCode.ERR_OK)
                return Mono.just(form);
            else
                return Mono.error(new AsrException(errCode));
        } catch (Exception ex) {
            return Mono.error(new AsrException(ErrorCode.ERR_PARAMS_MISSED.errid, ex.getMessage()));
        }
    }

    private static ErrorCode checkRequired(CreateTaskForm form) {
        ErrorCode errorCode = ErrorCode.ERR_PARAMS_MISSED;
        String error = "";

        if (StringUtils.isBlank(form.appId)) {
            error = "productId or app_id is empty";
        } 
//        else if (form.speakerNumber < -1 || form.speakerNumber > 16) {
//            error = "speaker_number must in range: [0, 16]. yours: " + form.speakerNumber;
//        } 
        else if (StringUtils.isBlank(form.AudioId)) {
            EAudioType audioType = EAudioType.fromKey(form.audioType);

            if (audioType == null || !(audioType == EAudioType.PCM || audioType == EAudioType.WAV)) {
                error = "audio_type is empty or not supported! current: " + form.audioType;
            } else if (StringUtils.isBlank(form.filePath)) {
                error = "file_path is empty";
            } else {
                try {
                    new URL(form.filePath);
                } catch (MalformedURLException e) {
                    error = "Invalid file_path: " + form.filePath;
                }

                if (form.channel > 1 && audioType != EAudioType.OGG_OPUS) {
                    error = "un-supported channel with current audio type: " + form.audioType;
                }
            }
        } else if (StringUtils.isNoneBlank(form.callback)) {
            try {
                new URL(form.callback);
            } catch (MalformedURLException e) {
                error = "Invalid callback: " + form.filePath;
            }
        }else if (StringUtils.isNoneBlank(form.userId)) {
            try {
                Integer.valueOf(form.userId); //目前暂时先校验这个userId
            } catch (NumberFormatException e) {
                error = "Invalid userId: " + form.userId;
            }
        }

        if (StringUtils.isBlank(error))
            errorCode = ErrorCode.ERR_OK;
        else
            errorCode.updateError(error);

        return errorCode;
    }
}
